/*
 *
 *  * Copyright:  2018 smarabbit studio.
 *  *
 *  *  Licensed under the Confluent Community License; you may not use this file
 *  *  except in compliance with the License.  You may obtain a copy of the License at
 *  *
 *  *  http://www.confluent.io/confluent-community-license
 *  *
 *  *  Unless required by applicable law or agreed to in writing, software
 *  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  *  specific language governing permissions and limitations under the License.
 *  *
 *  *  @作   者： 黄开晖 (117227773@qq.com)
 *  *  @日   期:    ${DATE}
 *
 */

/**
 * 
 */
package com.massyframework.beanskin.util.sorting.graph;

import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;

/**
 * {@link GraphFactory},图工厂
 * @author huangkh
 *
 */
public abstract class GraphFactory {

	/**
	 * 创建图
	 * @param <T>
	 * @param requireType {@link Class}
	 * @return {@link Graph}
	 */
	public static <T> Graph<T> createGraph(Class<T> requireType){
		return new GraphMatrix<T>();
	}

	/**
	 * 创建并填充图
	 * @param data {@link List}, 数据
	 * @param <T>
	 * @return {@link Graph}
	 */
	public static <T extends Comparable<T>> Graph<T> createAndFillGraph(List<T> data){
		Graph<T> result = new GraphMatrix<>();

		data.stream().forEach( value -> result.insert(value));
		int size = data.size();

		for (int i=0; i<size; i++ ){
			T o1 = data.get(i);

			for (int j= i+1; j<size; j++) {
				T o2 = data.get(j);

				int order = o1.compareTo(o2);

				switch (order) {
					case -1:{
						result.insert(o1, o2, new Edge(1, null));
						break;
					}case 1: {
						result.insert(o2, o1, new Edge(1, null));
						break;
					}
				}
			}
		}

		return result;
	}
	
	/**
	 * 创建并填充图
	 * @param data {@link List}, 数据
	 * @param comparator {@link Comparator},排序器
	 * @param <T>
	 * @return {@link Graph}
	 */
	public static <T> Graph<T> createAndFillGraph(List<T> data, Comparator<T> comparator){
		Graph<T> result = new GraphMatrix<>();

		data.stream().forEach( value -> result.insert(value));
		int size = data.size();

		for (int i=0; i<size; i++ ){
			T o1 = data.get(i);

			for (int j= i+1; j<size; j++) {
				T o2 = data.get(j);

				int order = comparator.compare(o1, o2);
				switch (order) {
					case -1:{
						result.insert(o1, o2, new Edge(1, null));
						break;
					}case 1: {
						result.insert(o2, o1, new Edge(1, null));
						break;
					}
				}
			}
		}

		return result;
	}

	/**
	 * 排序并返回排序结果
	 * @param data {@link List}, 需要排序的数据
	 * @param <T>
	 * @return {@link SortResult}
	 */
	public static <T extends Comparable<T>> SortResult<T> sort(List<T> data){
		Graph<T> graph = createAndFillGraph(data);

		SortResult<T> result = new SortResult<>();
	
		Predicate<Vertex<T>> filter = vertex -> vertex.getInDegree() == 0;
		List<T> tmp = graph.remove(filter);
		while (!tmp.isEmpty()) {
			result.addSorted(tmp);
			tmp = graph.remove( filter);
		}

		if (graph.vertexNumber() != 0) {
			filter = vertex -> {return true; };
			tmp = graph.remove( filter);
			result.setUnsort(tmp);
		}

		return result;
	}
	
	/**
	 * 排序并返回排序结果
	 * @param data {@link List}, 需要排序的数据
	 * @param comparator {@link Comparator}, 排序器
	 * @param <T>
	 * @return {@link SortResult}
	 */
	public static <T> SortResult<T> sort(List<T> data, Comparator<T> comparator){
		Graph<T> graph = createAndFillGraph(data, comparator);

		SortResult<T> result = new SortResult<>();
	
		Predicate<Vertex<T>> filter = vertex -> vertex.getInDegree() == 0;
		List<T> tmp = graph.remove(filter);
		while (!tmp.isEmpty()) {
			result.addSorted(tmp);
			tmp = graph.remove( filter);
		}

		if (graph.vertexNumber() != 0) {
			filter = vertex -> {return true; };
			tmp = graph.remove( filter);
			result.setUnsort(tmp);
		}

		return result;
	}
}
